package fr.cdj.thebox.client.app;

import java.util.Date;
import java.util.List;

import net.customware.gwt.presenter.client.EventBus;
import net.customware.gwt.presenter.client.widget.WidgetPresenter;

import com.google.gwt.user.client.Cookies;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.FormPanel.SubmitEvent;
import com.google.gwt.user.client.ui.FormPanel.SubmitHandler;
import com.google.inject.Inject;
import com.google.inject.Singleton;

import fr.cdj.thebox.client.app.ui.TheboxDisplay;
import fr.cdj.thebox.client.content.ContentPresenter;
import fr.cdj.thebox.client.events.DeleteFilesRequestEvent;
import fr.cdj.thebox.client.events.DeleteFilesRequestHandler;
import fr.cdj.thebox.client.events.DeleteFilesSuccessEvent;
import fr.cdj.thebox.client.events.ListFilesRequestEvent;
import fr.cdj.thebox.client.events.ListFilesRequestHandler;
import fr.cdj.thebox.client.events.ListFilesSuccessEvent;
import fr.cdj.thebox.client.events.LogoutEvent;
import fr.cdj.thebox.client.events.LogoutHandler;
import fr.cdj.thebox.client.menu.MenuPresenter;
import fr.cdj.thebox.client.services.FileAdminServiceAsync;
import fr.cdj.thebox.client.services.FileServiceAsync;
import fr.cdj.thebox.client.services.LoginServiceAsync;
import fr.cdj.thebox.shared.User;
import fr.cdj.thebox.shared.FileList;

@Singleton
public class TheboxPresenter extends WidgetPresenter<TheboxDisplay> {

	@Inject
	private MenuPresenter menuPresenter;

	@Inject
	private ContentPresenter contentPresenter;

	@Inject
	private FileServiceAsync service;

	@Inject
	private FileAdminServiceAsync adminService;

	@Inject
	private LoginServiceAsync loginService;

	@Inject
	public TheboxPresenter(TheboxDisplay display, EventBus eventBus) {
		super(display, eventBus);
	}

	@Override
	protected void onBind() {
		registerHandler(display.addLoginSubmitHandler(new SubmitHandler() {
			@Override
			public void onSubmit(SubmitEvent event) {
				String login = display.getLoginHasText().getText();
				String passwd = display.getPasswordHasText().getText();
				loginService.loginServer(login, passwd, new AsyncCallback<User>() {
					@Override
					public void onSuccess(User result) {
						String sessionID = result.getSessionId();
						final long DURATION = 1000 * 60 * 60 * 24 * 1;
						Date expires = new Date(System.currentTimeMillis() + DURATION);
						Cookies.setCookie("sid", sessionID, expires, null, "/", false);
						displayList(result);
						display.clearLogin();
					}

					@Override
					public void onFailure(Throwable arg0) {
						display.invalidLogin();
					}
				});
			}
		}));
		registerHandler(eventBus.addHandler(LogoutEvent.getType(), new LogoutHandler() {
			@Override
			public void onLogout(LogoutEvent event) {
				loginService.logout(new AsyncCallback<Void>() {
					@Override
					public void onSuccess(Void result) {
						display.showLogin(true);
					}

					@Override
					public void onFailure(Throwable arg0) {
						display.showLogin(true);
					}
				});
			}
		}));

		menuPresenter.bind();
		contentPresenter.bind();
		registerHandler(eventBus.addHandler(ListFilesRequestEvent.getType(), new ListFilesRequestHandler() {
			@Override
			public void onListFilesRequest(final ListFilesRequestEvent event) {
				String path = event.getPath();
				if (path != null) {
					listFiles(event.getEventSource(), path);
				}
			}
		}));
		registerHandler(eventBus.addHandler(DeleteFilesRequestEvent.getType(), new DeleteFilesRequestHandler() {
			@Override
			public void onDeleteFilesRequest(DeleteFilesRequestEvent event) {
				List<String> paths = contentPresenter.getSelectedPaths();
				if (!paths.isEmpty() && Window.confirm("Delete ?")) {
					deleteFiles(paths.toArray(new String[paths.size()]));
				}
			}
		}));
	}

	@Override
	protected void onUnbind() {
		menuPresenter.unbind();
		contentPresenter.unbind();
	}

	@Override
	protected void onRevealDisplay() {
		this.getDisplay().setMenuDisplay(menuPresenter.getDisplay());
		this.getDisplay().setContentDisplay(contentPresenter.getDisplay());
		menuPresenter.revealDisplay();
		contentPresenter.revealDisplay();

		String sessionID = Cookies.getCookie("sid");
		if (sessionID == null) {
			display.showLogin(true);
		} else {
			checkWithServerIfSessionIdIsStillLegal(sessionID);
		}
	}

	private void checkWithServerIfSessionIdIsStillLegal(String sessionID) {
		loginService.loginFromSessionServer(new AsyncCallback<User>() {
			@Override
			public void onFailure(Throwable caught) {
				display.showLogin(true);
			}

			@Override
			public void onSuccess(User result) {
				if (result == null) {
					display.showLogin(true);
				} else {
					displayList(result);
				}
			}
		});
	}

	private void displayList(User user) {
		menuPresenter.getDisplay().setShowDelete(user.isAdmin());
		display.showLogin(false);
		listFiles(contentPresenter, "");
	}

	private void listFiles(final Object source, final String path) {
		service.listFiles(path, new AsyncCallback<FileList>() {
			@Override
			public void onSuccess(FileList fileList) {
				eventBus.fireEvent(new ListFilesSuccessEvent(source, fileList));
			}

			@Override
			public void onFailure(Throwable caught) {
				Window.alert("File listing failed (" + path + ")");
			}
		});
	}

	private void deleteFiles(String[] paths) {
		adminService.deleteFiles(paths, new AsyncCallback<Void>() {
			@Override
			public void onSuccess(Void result) {
				eventBus.fireEvent(new DeleteFilesSuccessEvent());
			}

			@Override
			public void onFailure(Throwable caught) {
				Window.alert("File delete failed (protected)");
			}
		});
	}

}
